﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace IDEAMS.utils
{
    public class SHCollection<T>
    //where T : ICloneable
    {
        //  protected readonly object lockerObj = new object();

        protected ReaderWriterLockSlim rwLock = new ReaderWriterLockSlim();

        public List<T> dataList { get; }

        public virtual bool Equals(T obj, object key)
        {
            return false;
        }

        public virtual void CopyTo(T src, T dst)
        {

        }

        public SHCollection()
        {
            dataList = new List<T>();
        }

        public int Count()
        {
            rwLock.EnterReadLock();

            try
            {
                return dataList.Count;
            }
            finally
            {
                rwLock.ExitReadLock();
            }
        }

        public List<T> Where(Func<T, bool> func)
        {
            List<T> rn = new List<T>();

            rwLock.EnterReadLock();
            try
            {
                foreach (var v in dataList)
                {
                    if (func(v))
                    {
                        rn.Add(v);
                    }
                }
            }
            finally
            {
                rwLock.ExitReadLock();
            }


            return rn;
        }

        public bool Exists(Predicate<T> predicate)
        {
            rwLock.EnterReadLock();

            try
            {
                return dataList.Exists(predicate);
            }
            finally
            {
                rwLock.ExitReadLock();
            }
        }
        public void ForEach(Func<T, bool> func)
        {
            rwLock.EnterReadLock();

            try
            {
                foreach (var v in dataList)
                {
                    if (func(v)) break;
                }
            }
            finally
            {
                rwLock.ExitReadLock();
            }
        }

        public int Update(object key, T newObj)
        {
            int rn = 0;

            rwLock.EnterWriteLock();

            try
            {
                T oldObj = dataList.Where(x => Equals(x, key)).FirstOrDefault();
                if (oldObj != null)
                {
                    CopyTo(newObj, oldObj);
                }

            }
            catch (Exception)
            {
                rn = -1;
            }
            finally
            {
                rwLock.ExitWriteLock();
            }

            return rn;
        }

        public int Delete(T obj)
        {
            int rn = 0;

            rwLock.EnterWriteLock();
            try
            {
                dataList.Remove(obj);
            }
            catch (Exception)
            {
                rn = -1;
            }
            finally
            {
                rwLock.ExitWriteLock();
            }

            return rn;
        }

        public int Delete(object key)
        {
            int rn = 0;
            rwLock.EnterWriteLock();
            try
            {

                T s = dataList.Where(x => Equals(x, key)).FirstOrDefault();
                if (s != null) dataList.Remove(s);
            }
            catch (Exception)
            {
                rn = -1;
            }
            finally
            {
                rwLock.ExitWriteLock();
            }

            return rn;
        }

        public int Add(T obj)
        {
            int rn = 0;
            rwLock.EnterWriteLock();
            try
            {
                dataList.Add(obj);
            }
            catch (Exception)
            {
                rn = -1;
            }
            finally
            {
                rwLock.ExitWriteLock();
            }

            return rn;
        }

        public T Find(object key)
        {
            T rn = default(T);

            rwLock.EnterReadLock();
            try
            {
                rn = dataList.Where(x => Equals(x, key)).FirstOrDefault();
            }
            catch (Exception)
            {
                rn = default(T);
            }
            finally
            {
                rwLock.ExitReadLock();
            }

            return rn;
        }

        public T GetCopy(object key)
        {
            T rn = default(T);

            rwLock.EnterReadLock();
            try
            {
                T src = dataList.Where(x => Equals(x, key)).FirstOrDefault();
                CopyTo(src, rn);
            }
            catch (Exception)
            {
                rn = default(T);
            }
            finally
            {
                rwLock.ExitReadLock();
            }

            return rn;
        }

        public void Clear()
        {
            rwLock.EnterWriteLock();
            try
            {

                dataList.Clear();
            }
            catch (Exception)
            {
            }
            finally
            {
                rwLock.ExitWriteLock();
            }
        }

        public List<T> ToList()
        {
            List<T> rn = null;

            rwLock.EnterReadLock();
            try
            {
                rn = dataList.ToList();
            }
            catch (Exception)
            {
                rn = null;
            }
            finally
            {
                rwLock.ExitReadLock();
            }

            return rn;
        }
    }
}
